7

引述

最近看设计模式以及laravel代码,对于控制反转以及依赖注入这些概念非常困惑,于是找了一些资料,以下是对于控制反转的一下理解。

概念

IoC

控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转移,从程序代码本身转移到了外部容器。其中最常见的方式叫做依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。通过控制反转,对象在被创建的时候,由一个调控系统内所有对象的外界实体,将其所依赖的对象的引用传递给它。也可以说,依赖被注入到对象中。

正如概念中描述的,那么控制反转具体指哪些 控制反转 了呢,其实我理解的控制反转是指程序所控制的对象的控制权交给了容器,而这个容器就是实现各个模块解耦合的关键。IoC只是一种设计思想,主要实现有:

  • 依赖查找(Dependency Lookup):容器提供回调接口和上下文环境给组件。
  • 依赖注入(Dependency Injection)

我们着重说一下依赖注入。

DI

在软件工程中,依赖注入是种实现控制反转用于解决依赖性设计模式。一个依赖关系指的是可被利用的一种对象(即服务提供端) 。依赖注入是将所依赖的传递给将使用的从属对象(即客户端)。该服务是将会变成客户端的状态的一部分。 传递服务给客户端,而非允许客户端来建立或寻找服务,是本设计模式的基本要求。

以上是wikipedia上对于依赖注入的理解,下面将用实际的例子详细讲解。

举例

加入我们设计一个通用的用户登录基类,可以支持多个平台的用户登录
那么最糟糕的写法是,

/**
 * A类用户登录
 **/
class User_A_Login
{
    public function checkALogin(){
        
    };
}

/**
 * B类用户登录
 **/
class User_B_Login
{
    public function checkBLogin(){
        
    };
}
/**
 * 登录基类
 **/
class User_Login
{
    public function checkLogin($userType)
    {
        if($userType = 'A'){
            $this->objAUser = new User_A_Login();
            $this->objAUser->checkALogin();
        }elseif($userType = 'B'){
            $this->objBUser = new User_B_Login();
            $this->objBUser->checkBLogin();
        }
    }
}

上面的 User_Login 这个类就直接依赖于类 User_A_LoginUser_B_Login ,如果我们使用下面这种方式写


interface User_Login_Interface
{
    public function checkLogin();
}
/**
 * A类用户登录
 **/
class User_A_Login implements User_Login_Interface
{
    public function checkLogin(){
        
    };
}

/**
 * B类用户登录
 **/
class User_B_Login implements User_Login_Interface
{
    public function checkLogin(){
        
    };
}
/**
 * 登录基类
 **/
class User_Login
{
    public $userLogin;
    
    public function setUser(User_Login_Interface $user){
        $this->userLogin = $user;
    }
    
    public function checkLogin()
    {
        $this->userLogin->checkLogin();
    }
}

如果按照这种方式进行构建代码,我们将依赖项User_B_Login或者User_A_Login通过函数 setUser( ) 注入到类中,调用方式:

$userLogin = new User_Login();
$userLogin->setUser(new User_A_Login);
$userLogin->checkLogin();

调用方可以控制使用那个登录类型,这就完成了对于不同登录系统的依赖注入。如果你引入了一个新的用户c,只需写一个c的登录类:

/**
 * C类用户登录
 **/
class User_C_Login implements User_Login_Interface
{
    public function checkLogin(){
        
    };
}

就可以通过:

$userLogin = new User_Login();
$userLogin->setUser(new User_C_Login);
$userLogin->checkLogin();

进行登录验证了。在实际代码中由于基类非常复杂需要对登录做一系列处理,所以每次添加登录用户不应该去修改基类。对于一下框架例如laravel的框架是不能修改的,应该就是通过这种方式实现的调用方的自定义。


estu
23 声望4 粉丝

我一个人,就是一只军队